<?php
/**
 * @author jonathan <jo.link.noir@gmail.com>
 * @version 1.0: jo_link_noir
 * @date 18-06-2010
 */
class U1_DAO_Move extends SW_DAO
{
	/* @var {id => SW_Planet_Element, ...}*/
	//static private $moves = array();


	/**
	 * @param int $player_sends
	 * @param int $player_target
	 * @param string $order
	 * @param int $start_planet
	 * @param int $end_planet
	 * @param int $duration
	 * @param int $time_end
	 * @param U1_Units $army
	 * @param array $conso
	 * @param U1_Resource $resource
	 * @param int $time_ref
	 * @param array $transport = null
	 * @return int : id
	 */
	static public function addMove($player_sends, $player_target, $order, $start_planet, $end_planet, $duration, $time_end, U1_Units $army, array $conso, U1_Resource $resource, $time_ref, array $transport = null)
	{
		if (false === isset(self::$queries[__METHOD__]))
		{
			self::$queries[__METHOD__] = self::$db->prepare(
				'INSERT INTO move(player_sends, player_target, `order`, start_planet, end_planet, duration, time_end, data) VALUES(?,?,?,?,?,?,?,?)'
			);
		}

		//transport / base / colonise
		if ($transport)
		{
			$data = serialize(array($army, $transport));
			SF_Process_Array::increase($transport, SF_Process_Array::shiftKey($conso,2));
		}
		//espionnage / attaque
		else
		{
			if ($order === 'attack')
			{
				$stats = array();
				foreach ($army as $group => $unit)
					if ($unit->stats)
						$stats[$group] = $unit->stats;
				$data = serialize(array($army, $stats));
			}
			else
				$data = serialize(array($army, array()));

			$transport[2] = $conso[0];
			$transport[3] = $conso[1];
		}

		try
		{
			self::$db->beginTransaction();

			//enlève les vaisseaux
			U1_Army_DAO::getFactory()->decrease($start_planet, $army);

			//enlève les ressources
			if ($resource)
				$resource->decrease($transport, $time_ref);

			//lance la flotte
			self::$queries[__METHOD__]->execute(array(
				(int)$player_sends, (int)$player_target, $order, (int)$start_planet, (int)$end_planet, (int)$duration, (int)$time_end, $data
			));

			self::$db->commit();
			return (int)self::$db->lastInsertId();
		}
		catch (Exception $e)
		{
			self::$db->rollBack();
			throw $e;
		}
	}

	/**
	 * @param string $where
	 * @param int $limit : limite de résultat
	 * @return array : {id => {id:int, player_sends:int, player_target:int, order:string, start_planet:int, end_planet:int, duration:int, time_end:int, data:string, army:U1_Move_Units}:StdClass, ...}
	 */
	static protected function prepareMove($where, $limit)
	{
		$moves = $removeIds = array();
		foreach (self::$db->query(
			'SELECT id, player_sends, player_target, `order`, start_planet, end_planet, duration, time_end, data
			FROM move WHERE '.$where.' ORDER BY time_end LIMIT 0, '.((int)$limit),
			PDO::FETCH_OBJ
		) as $m)
		{
			//si un des joueurs lié à la flotte existe
			if (U1_DAO_User::select($m->player_sends) || U1_DAO_User::select($m->player_target))
			{
				$m->id				= (int)$m->id;
				$m->player_sends 	= (int)$m->player_sends;
				$m->player_target	= (int)$m->player_target;
				$m->start_planet	= (int)$m->start_planet;
				$m->end_planet		= (int)$m->end_planet;
				$m->duration		= (int)$m->duration;
				$m->time_end		= (int)$m->time_end;
				$m->army			= unserialize($m->data);

				//créé le mouvement
				if ($m->order === 'attack')
				{
					$move = new U1_Move_Attack($m->end_planet, $m->time_end);
					$stats = &$m->army[1];
					foreach ($m->army[0] as $g => $unit)
						$unit->stats = $stats[$g];
				}
				else if ($m->order === 'spy')
				{
					$move = new U1_Move_Spy($m->end_planet, $m->time_end);
				}
				else
				{
					$move = U1_Move::getMoving(
						$m->order,
						$m->end_planet,
						empty($m->army[1]) ? null : new U1_Removable_Resource($m->army[1]),
						$m->time_end
					);
					//$move->playerTarget = $m->player_target;
				}
				$m->army = $m->army[0];
				$move->id = $m->id;
				$move->duration = $m->duration;
				$move->player_sends = $m->player_sends;
				$move->player_target = $m->player_target;

				$m->army = new U1_Move_Units($m->start_planet, $m->army, $move);
				$moves[] = $m;
			}
			else
				$removeIds[] = $m->id;
		}

		if (!empty($removeIds))
			self::_deleteIds($removeIds);

		return $moves;
	}

	/**
	 * Termine les mouvement arrivés
	 * @param U1_Player|U1_Player $player
	 * @param int $limit : limite de résultat
	 * @param bool $returnMoveUnits = true
	 * @return array : {id => {id:int, player_sends:int, player_target:int, order:string, start_planet:int, end_planet:int, duration:int, time_end:int, data:string, army:U1_Move_Units}:StdClass, ...}|{id => U1_Move_Units, …}
	 */
	static public function selectLinkPlayer($player, $limit, $returnMoveUnits = true)
	{
		$id = ($player instanceof U1_Player) ? $player->getId() : (int)$id;
		$return = self::prepareMove('player_sends='.$id.' OR player_target='.$id, $limit);

		if (!$returnMoveUnits)
			foreach ($return as &$v)
				$v = $v['army'];

		return $return;
	}

	/**
	 * Termine les mouvement arrivés
	 * @param int $timeRef : récupère tout les mouvements terminé avant le temps présicé
	 * @param int $limit : limite de résultat
	 * @return array : {id => {id:int, player_sends:int, player_target:int, order:string, start_planet:int, end_planet:int, duration:int, time_end:int, data:string, army:U1_Move_Units}:StdClass, ...}
	 */
	static public function selectArrived($timeRef, $limit)
	{
		return self::prepareMove('time_end <= '.((int)$timeRef), $limit);
	}

	/**
	 * @param array $ids
	 * @return bool
	 */
	final static protected function _deleteIds(array $ids)
	{
		return self::$db->query('DELETE FROM move WHERE id IN ('.implode(',',$ids).')');
	}

	/**
	 * @param array $ids
	 * @return bool
	 */
	static public function deleteIds(array $ids)
	{
		foreach ($ids as &$id)
			$id = (int)$id;
		return self::_deleteIds($ids);
	}

	/**
	 * Fait revenir la flotte en créant un U1_Transport avec l'ordre base
	 * @param SW_Units $units
	 * @param SW_Move $move
	 * @param U1_Removable_Resource $resource = null : prid en compte si $move n'est pas un U1_Transport
	 */
	static public function baseSend(SW_Units $units, SW_Move $move, U1_Removable_Resource $resource = null)
	{
		if (false === isset(self::$queries[__METHOD__]))
		{
			self::$queries[__METHOD__] = self::$db->prepare(
				'UPDATE move SET player_target=player_sends, `order`="base", start_planet=end_planet, end_planet=?, time_end=time_end+duration, data=? WHERE id = ?'
			);
		}

		$removable = ($move instanceof U1_Transport)
			? $move->getRemovable('U1_Removable_Resource')
			: $resource;
		$moveBase = new U1_Move_Base(
			$move->getStartPoint(),
			$removable,
			$move->getTime() + $move->duration
		);
		$moveBase->setStartPoint($move->getEndPoint());
		$moveBase->duration = $move->duration;
		$moveBase->id = $move->id;
		$moveBase->player_target = $moveBase->player_sends = $move->player_sends;
		$move->setNext($moveBase);

		self::$queries[__METHOD__]->execute(array(
			$moveBase->getStartPoint(),
			serialize(array($units, $removable?$removable->getQuantities():array())),
			$move->id
		));
	}

	/**
	 * @param int $id
	 */
	static public function deleteId($id)
	{
		if (false === isset(self::$queries[__METHOD__]))
		{
			self::$queries[__METHOD__] = self::$db->prepare(
				'DELETE FROM move WHERE id = ?'
			);
		}

		self::$queries[__METHOD__]->execute(array(
			(int)$id
		));
	}
}